vulkan: Add proof-of-concept clip implementation
authorBenjamin Otte <otte@redhat.com>
Sat, 24 Dec 2016 05:16:54 +0000 (06:16 +0100)
committerBenjamin Otte <otte@redhat.com>
Sat, 24 Dec 2016 05:19:16 +0000 (06:19 +0100)
We can now clip to cicular rounded rectangles when drawing colors.

gsk/gskvulkanrender.c
gsk/gskvulkanrenderpass.c
gsk/gskvulkanrenderprivate.h
gsk/resources/vulkan/color-clip-rounded.frag.glsl [new file with mode: 0644]
gsk/resources/vulkan/color-clip-rounded.frag.spv [new file with mode: 0644]
gsk/resources/vulkan/color-clip-rounded.vert.glsl [new file with mode: 0644]
gsk/resources/vulkan/color-clip-rounded.vert.spv [new file with mode: 0644]

index e2e8167b4c84c1c7e73f67a015195c13da98f22e..d23ff8cd3edcc207e5a9b8d5257ca8cf00d226c0 100644 (file)
@@ -314,7 +314,8 @@ gsk_vulkan_render_get_pipeline (GskVulkanRender       *self,
     GskVulkanPipeline * (* create_func) (GskVulkanPipelineLayout *layout, const char *name, VkRenderPass render_pass);
   } pipeline_info[GSK_VULKAN_N_PIPELINES] = {
     { "blit", gsk_vulkan_blend_pipeline_new },
-    { "color", gsk_vulkan_color_pipeline_new }
+    { "color", gsk_vulkan_color_pipeline_new },
+    { "color-clip-rounded", gsk_vulkan_color_pipeline_new }
   };
 
   g_return_val_if_fail (type < GSK_VULKAN_N_PIPELINES, NULL);
index dc26f31f1c89a88e6a07c04bd2352f69ab0bbd59..21a5cb9c88578c38364a1e93c6ee3e9883f8014e 100644 (file)
@@ -98,6 +98,7 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
     .type = GSK_VULKAN_OP_FALLBACK,
     .render.node = node
   };
+  GskVulkanPipelineType pipeline_type;
 
   switch (gsk_render_node_get_node_type (node))
     {
@@ -126,10 +127,14 @@ gsk_vulkan_render_pass_add_node (GskVulkanRenderPass           *self,
       return;
 
     case GSK_COLOR_NODE:
-      if (!gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+      if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR;
+      else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+        pipeline_type = GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED;
+      else
         FALLBACK ("Color nodes can't deal with clip type %u\n", constants->clip.type);
       op.type = GSK_VULKAN_OP_COLOR;
-      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, GSK_VULKAN_PIPELINE_COLOR);
+      op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
       g_array_append_val (self->render_ops, op);
       return;
 
index e44f2639f26d72b723cbd56fdfc0ed43f4092828..c5f7379daf6b77ca620cf70b1e430e2f15f9aeee 100644 (file)
@@ -12,6 +12,7 @@ G_BEGIN_DECLS
 typedef enum {
   GSK_VULKAN_PIPELINE_BLIT,
   GSK_VULKAN_PIPELINE_COLOR,
+  GSK_VULKAN_PIPELINE_COLOR_CLIP_ROUNDED,
   /* add more */
   GSK_VULKAN_N_PIPELINES
 } GskVulkanPipelineType;
diff --git a/gsk/resources/vulkan/color-clip-rounded.frag.glsl b/gsk/resources/vulkan/color-clip-rounded.frag.glsl
new file mode 100644 (file)
index 0000000..9825f78
--- /dev/null
@@ -0,0 +1,51 @@
+#version 420 core
+
+layout(location = 0) in vec2 inPos;
+layout(location = 1) in vec4 inColor;
+layout(location = 2) in vec4 inClipBounds;
+layout(location = 3) in vec4 inClipWidths;
+
+layout(location = 0) out vec4 color;
+
+struct RoundedRect {
+  vec4 bounds;
+  vec4 corners;
+};
+
+float clip(vec2 pos, RoundedRect r) {
+  vec2 ref_tl = r.bounds.xy + vec2( r.corners.x,  r.corners.x);
+  vec2 ref_tr = r.bounds.zy + vec2(-r.corners.y,  r.corners.y);
+  vec2 ref_br = r.bounds.zw + vec2(-r.corners.z, -r.corners.z);
+  vec2 ref_bl = r.bounds.xw + vec2( r.corners.w, -r.corners.w);
+  
+  float d_tl = distance(pos, ref_tl);
+  float d_tr = distance(pos, ref_tr);
+  float d_br = distance(pos, ref_br);
+  float d_bl = distance(pos, ref_bl);
+
+  float pixels_per_fragment = length(fwidth(pos.xy));
+  float nudge = 0.5 * pixels_per_fragment;
+  vec4 distances = vec4(d_tl, d_tr, d_br, d_bl) - r.corners + nudge;
+
+  bvec4 is_out = bvec4(pos.x < ref_tl.x && pos.y < ref_tl.y,
+                       pos.x > ref_tr.x && pos.y < ref_tr.y,
+                       pos.x > ref_br.x && pos.y > ref_br.y,
+                       pos.x < ref_bl.x && pos.y > ref_bl.y);
+
+  float distance_from_border = dot(vec4(is_out),
+                                   max(vec4(0.0, 0.0, 0.0, 0.0), distances));
+
+  // Move the distance back into pixels.
+  distance_from_border /= pixels_per_fragment;
+  // Apply a more gradual fade out to transparent.
+  //distance_from_border -= 0.5;
+
+  return 1.0 - smoothstep(0.0, 1.0, distance_from_border);
+}
+
+void main()
+{
+    RoundedRect r = RoundedRect(vec4(inClipBounds.xy, inClipBounds.xy + inClipBounds.zw), inClipWidths);
+
+    color = vec4(inColor.rgb * inColor.a, inColor.a) * clip (inPos, r);
+}
diff --git a/gsk/resources/vulkan/color-clip-rounded.frag.spv b/gsk/resources/vulkan/color-clip-rounded.frag.spv
new file mode 100644 (file)
index 0000000..cf650af
Binary files /dev/null and b/gsk/resources/vulkan/color-clip-rounded.frag.spv differ
diff --git a/gsk/resources/vulkan/color-clip-rounded.vert.glsl b/gsk/resources/vulkan/color-clip-rounded.vert.glsl
new file mode 100644 (file)
index 0000000..a3c5535
--- /dev/null
@@ -0,0 +1,36 @@
+#version 420 core
+
+layout(location = 0) in vec4 inRect;
+layout(location = 1) in vec4 inColor;
+
+layout(push_constant) uniform PushConstants {
+    mat4 mvp;
+    vec4 clip_bounds;
+    vec4 clip_widths;
+    vec4 clip_heights;
+} push;
+
+layout(location = 0) out vec2 outPos;
+layout(location = 1) out flat vec4 outColor;
+layout(location = 2) out flat vec4 outClipBounds;
+layout(location = 3) out flat vec4 outClipWidths;
+
+out gl_PerVertex {
+  vec4 gl_Position;
+};
+
+vec2 offsets[6] = { vec2(0.0, 0.0),
+                    vec2(1.0, 0.0),
+                    vec2(0.0, 1.0),
+                    vec2(0.0, 1.0),
+                    vec2(1.0, 0.0),
+                    vec2(1.0, 1.0) };
+
+void main() {
+  vec2 pos = inRect.xy + inRect.zw * offsets[gl_VertexIndex];
+  gl_Position = push.mvp * vec4 (pos, 0.0, 1.0);
+  outPos = pos;
+  outColor = inColor;
+  outClipBounds = push.clip_bounds;
+  outClipWidths = push.clip_widths;
+}
diff --git a/gsk/resources/vulkan/color-clip-rounded.vert.spv b/gsk/resources/vulkan/color-clip-rounded.vert.spv
new file mode 100644 (file)
index 0000000..4414e99
Binary files /dev/null and b/gsk/resources/vulkan/color-clip-rounded.vert.spv differ